package com.turn.ttorrent.common.protocol;

/**
 * Base interface for announce request messages.
 *
 * <p>
 * This interface must be implemented by all subtypes of announce request
 * messages for the various tracker protocols.
 * </p>
 *
 * For details information see <a href="https://wiki.theory.org/index.php/BitTorrentSpecification#Tracker_Request_Parameters"></a>
 *
 * @author mpetazzoni
 */
public interface AnnounceRequestMessage {

  int DEFAULT_NUM_WANT = 50;

  /**
   * Announce request event types.
   *
   * <p>
   * When the client starts exchanging on a torrent, it must contact the
   * torrent's tracker with a 'started' announce request, which notifies the
   * tracker this client now exchanges on this torrent (and thus allows the
   * tracker to report the existence of this peer to other clients).
   * </p>
   *
   * <p>
   * When the client stops exchanging, or when its download completes, it must
   * also send a specific announce request. Otherwise, the client must send an
   * eventless (NONE), periodic announce request to the tracker at an
   * interval specified by the tracker itself, allowing the tracker to
   * refresh this peer's status and acknowledge that it is still there.
   * </p>
   */
  enum RequestEvent {
    NONE(0),
    COMPLETED(1),
    STARTED(2),
    STOPPED(3);

    private final int id;

    RequestEvent(int id) {
      this.id = id;
    }

    public String getEventName() {
      return this.name().toLowerCase();
    }

    public int getId() {
      return this.id;
    }

    public static RequestEvent getByName(String name) {
      for (RequestEvent type : RequestEvent.values()) {
        if (type.name().equalsIgnoreCase(name)) {
          return type;
        }
      }
      return null;
    }

    public static RequestEvent getById(int id) {
      for (RequestEvent type : RequestEvent.values()) {
        if (type.getId() == id) {
          return type;
        }
      }
      return null;
    }
  }

  /**
   * @return SHA1 hash of value associated with "info" key in .torrent file
   */
  byte[] getInfoHash();

  /**
   * String representation of {@link #getInfoHash} where each byte replaced by hex-string value with lead zero
   * for example for byte array [1, 2, 15, -2] this method must return 01020FFE
   *
   * @return String representation of {@link #getInfoHash}
   */
  String getHexInfoHash();

  /**
   * @return peer id generated by current client
   */
  byte[] getPeerId();

  /**
   * @return String representation of {@link #getPeerId}. It's similarly {@link #getHexInfoHash()} method
   */
  String getHexPeerId();

  /**
   * @return current client port on which it listens for new connections
   */
  int getPort();

  /**
   * @return count of uploaded bytes for current torrent by current peer after sending STARTED event to the tracker
   */
  long getUploaded();

  /**
   * @return count of downloaded bytes for current torrent by current peer after sending STARTED event to the tracker
   */
  long getDownloaded();

  /**
   * @return count of bytes which client must be download
   */
  long getLeft();

  /**
   * Tells that it's compact request.
   * In this case tracker return compact peers list which contains only address and port without peer id,
   * but according to specification some trackers can ignore this parameter
   *
   * @return true if it's compact request.
   */
  boolean isCompact();

  /**
   * Tells that tracker can omit peer id field in response. This parameter is ignored if {@link #isCompact()} method
   * return true
   *
   * @return true if tracker can omit peer id
   */
  boolean canOmitPeerId();

  /**
   * @return event of current request
   */
  RequestEvent getEvent();

  /**
   * Optional. If it's not specified thet tracker get ip address from request
   *
   * @return current client address on which it listens for new connections
   */
  String getIp();

  /**
   * Optional. If it's not specified (value is zero or negative) tracker return default peers count. As a rule this count is 50
   *
   * @return count of peers which client want to get from tracker
   */
  int getNumWant();

  /**
   * Optional. Contains key of current client. Client can use this key for confirm for tracker that it's old client
   * after change IP address
   *
   * @return key of current client.
   */
  String getKey();

  /**
   * Optional. If previous response from tracker contains tracker id field, then client must send this value here
   *
   * @return previous tracker id
   */
  String getTrackerId();

}
